<!DOCTYPE html>


<html lang="zh-Hans">
  

    <head>
      <meta charset="utf-8" />
       
      <meta name="keywords" content="博客，代码，思考，生活" />
       
      <meta name="description" content="笔记汇总" />
      
      <meta
        name="viewport"
        content="width=device-width, initial-scale=1, maximum-scale=1"
      />
      <title>java基础随笔1 |  Zhang Shuo&#39;s Studio</title>
  <meta name="generator" content="hexo-theme-ayer">
      
      <link rel="shortcut icon" href="/hexo1/favicon.ico" />
       
<link rel="stylesheet" href="/hexo1/dist/main.css">

      <link
        rel="stylesheet"
        href="https://cdn.jsdelivr.net/gh/Shen-Yu/cdn/css/remixicon.min.css"
      />
      
<link rel="stylesheet" href="/hexo1/css/custom.css">
 
      <script src="https://cdn.jsdelivr.net/npm/pace-js@1.0.2/pace.min.js"></script>
       
 

      <link
        rel="stylesheet"
        href="https://cdn.jsdelivr.net/npm/@sweetalert2/theme-bulma@5.0.1/bulma.min.css"
      />
      <script src="https://cdn.jsdelivr.net/npm/sweetalert2@11.0.19/dist/sweetalert2.min.js"></script>

      <!-- mermaid -->
      
      <style>
        .swal2-styled.swal2-confirm {
          font-size: 1.6rem;
        }
      </style>
    <link rel="alternate" href="/hexo1/atom.xml" title="Zhang Shuo's Studio" type="application/atom+xml">
</head>
  </html>
</html>


<body>
  <div id="app">
    
      
    <main class="content on">
      <section class="outer">
  <article
  id="post-java基础/随笔"
  class="article article-type-post"
  itemscope
  itemprop="blogPost"
  data-scroll-reveal
>
  <div class="article-inner">
    
    <header class="article-header">
       
<h1 class="article-title sea-center" style="border-left:0" itemprop="name">
  java基础随笔1
</h1>
 

      
    </header>
     
    <div class="article-meta">
      <a href="/hexo1/2019/08/13/java%E5%9F%BA%E7%A1%80/%E9%9A%8F%E7%AC%94/" class="article-date">
  <time datetime="2019-08-13T09:00:00.000Z" itemprop="datePublished">2019-08-13</time>
</a> 
  <div class="article-category">
    <a class="article-category-link" href="/hexo1/categories/java%E5%9F%BA%E7%A1%80/">java基础</a>
  </div>
  
<div class="word_count">
    <span class="post-time">
        <span class="post-meta-item-icon">
            <i class="ri-quill-pen-line"></i>
            <span class="post-meta-item-text"> Word count:</span>
            <span class="post-count">6.5k</span>
        </span>
    </span>

    <span class="post-time">
        &nbsp; | &nbsp;
        <span class="post-meta-item-icon">
            <i class="ri-book-open-line"></i>
            <span class="post-meta-item-text"> Reading time≈</span>
            <span class="post-count">25 min</span>
        </span>
    </span>
</div>
 
    </div>
      



  
    <div class="article-entry" itemprop="articleBody">
       
  <p><strong>Scanner</strong></p>
<p>Scanner sc = new Scanner(System.in);</p>
<p>int num = sc.nextInt(); long num1 = sc.nextLong(); double num2 = sc.nextDouble(); float num3 = sc.nextFloat(); String str = sc.next(); //输入字符串并赋给str</p>
<p><strong>System类：</strong></p>
<p>（1）System.in：”标准”输入流。此流已打开并准备提供输入数据。通常，此流对应于键盘输入或者由主机环境或用户指定的另一个输入源。</p>
<p>（2）System.out：”标准”输出流。此流已打开并准备接受输出数据。</p>
<p>（3）static long currentTimeMillis()：返回以毫秒为单位的当前时间，</p>
<p>long time_now = System.currentTimeMillis()</p>
<p><strong>Random</strong></p>
<p>new Random().nextInt(int n);</p>
<p>范围是 [0,n)</p>
<p>public class Random1 { public static void main(String[] args) { for (int i = 0; i &lt; 100; i++) { //nextDouble和nextFloat是没有参数的 System.out.println(new Random().nextInt(2)); } } }</p>
<p>二、<strong>单例模式</strong>：软件的运行有且仅有一个实例化对象，也就是只会new一次</p>
<p><strong>构造器是私有的</strong></p>
<p>懒汉式和饿汉式区别是对象什么时候创建</p>
<p>饿汉式：在<strong>类加载之后还没调用getInstance()前</strong>就先new好一个对象，每次（包括第一次）调用该函数都返回之前new好的对象</p>
<p>懒汉式：当<strong>第一次调用getInstance()方法时</strong>来new对象，之后每次调用该函数都返回之前new好的对象</p>
<ol>
<li>饿汉模式：</li>
</ol>
<p>public class Single { // 不能是private static Single private Single() { } private static Single single=new Single(); // 只有用static才可以用类名.方法 public static Single getInstance() { return single; } } public class test1 { public static void main(String[] args) { s1 = new Single(); //报错 Single.single(); //报错 Single s3 = Single.getInstance(); Single s4 = Single.getInstance(); Single s5 = Single.getInstance(); // 这三个都指向同一个实例对象 } }</p>
<ol start="2">
<li>懒汉模式：</li>
</ol>
<p>public class Single { // 不能是private static Single private Single() { } private static Single single = null; public static Single getInstance() { if(single==null) { single = new Single(); return single; }else { return single; } } }</p>
<p><strong>三、初始化块：</strong></p>
<ol>
<li><p>初始化块（代码块）作用：对Java对象进行初始化</p>
</li>
<li><p>程序的执行顺序：</p>
</li>
</ol>
<p>（1）声明成员变量的默认值，例如下例的String name</p>
<p>（2）显式初始化、多个初始化块依次被执行</p>
<p>（3）构造器再对成员进行赋值操作</p>
<ol start="3">
<li>例如：</li>
</ol>
<p>public class Person{ String name; public Person(){ this.name=&quot;张三&quot;; System.out.prinln(&quot;1&quot;); } // 非静态的代码块 { System.out.println(&quot;2&quot;); } { System.out.println(&quot;3&quot;); } } // 执行new Person()后输出是：2 3 1</p>
<p><strong>四、final：</strong></p>
<ol>
<li>final标记的类不能被继承</li>
</ol>
<p>final标记的方法不能被子类重写</p>
<p>final标记的变量即成为常量，，名称大写</p>
<p><strong>常量没有默认值，必须手动赋值</strong>，因为一旦有值永远不可变。</p>
<ol start="2">
<li>用final修饰方法，方法体内就不能用this</li>
</ol>
<p>public class TestPerson{ int age; final String NAME = &quot;&quot;; // 常量必须显示赋值 // 常量定义名称约定使用大写,多个单词组成则使用_链接 // final在前,static在后 // 一起修饰就是全局常量 final static String NAME_1 =&quot;&quot;; public static void main(String[] args){ final int i=0; // 任何地方都可final } }</p>
<p><strong>五、抽象类：</strong></p>
<p>随着继承层次中一个个新子类的定义，类变得越来越具体，而父类更一般更通用。有的时候将一个父辈设计的非常抽象，以至于它没有具体的实例。</p>
<p>例如：不建立Animal类的实例对象，只建立Dog,Fish,Bird等的实例，Animal类就是抽象类</p>
<ol>
<li>用abstract关键字来修饰一个类时，这个类叫做抽象类。</li>
</ol>
<p>用abstract来修饰一个方法时，该方法叫做抽象方法。</p>
<p>*抽象方法：只有方法的声明没有方法的实现，以分号结束：abstrac int abstracMethod(int a)；</p>
<ol start="2">
<li><p>含有抽象方法的类必须被声明为抽象类</p>
</li>
<li><p><strong>抽象类不能被实例化</strong>。抽象类是用来作为父类被继承的，抽象类的子类必须重写抽象类的所有抽象方法，并提供方法体，若没有重写全部的抽象方法，仍为抽象类</p>
</li>
<li><p><strong>不能用abstract修饰属性</strong>，私有方法，构造器，静态方法，final的方法</p>
</li>
</ol>
<p>public abstract class Animal { public abstract void test(); public abstract void eat(); //public abstract int a; //报错，抽象类不能有属性 //下述这个是允许的，但不可以Animal.b调用，也不能Dog.b，只能dog.b //要想Dog.b调用，只能在Animal类中改为public static int b; public int b; }</p>
<p>编程软件快捷键： 先写出下面内容的第一行，点击报错(下面有波浪线)的地方，可以自动重写抽象类的方法：</p>
<p>public class Dog extends Animal{} @Override public void test() { // TODO Auto-generated method stub } @Override public void eat() { System.out.println(&quot;Dog eat!&quot;); } }</p>
<ol start="5">
<li><p>抽象类不能用final关键字声明，前者不能被实例化且子类必须重写父类所有抽象方法并提供方法体，后者不能被继承</p>
</li>
<li><p>抽象类中可以定义构造器吗？</p>
</li>
</ol>
<p>抽象类中可以有构造方法，只是不能直接创建抽象类的实例对象而已。new Vihicle()是非法的</p>
<p>六、模板设计模式：</p>
<ol>
<li><p>抽象类体现的就是一种模板模式的设计，抽象类作为多个子类的通用模板，子类在抽象类的基础上进行扩展改造，但子类总体上会保留抽象类的行为方式。</p>
</li>
<li><p>解决的问题：</p>
</li>
</ol>
<p>（1）当功能内部一部分实现是确定，一部分实现是不确定的，这时可以把不确定的部分暴露出去，让子类去实现</p>
<p>（2）编写一个抽象父类，父类提供了多个子类的通用方法，并把一个或多个方法留给其子类实现，就是一种模板模式</p>
<p>3.</p>
<p>public abstract class Template{ //计算代码花费的时间 public final void spendTime() { long start = System.currentTimeMillis(); code(); //调用子类重写方法 long end = System.currentTimeMillis(); System.out.println(&quot;程序花费的时间为:&quot;+(end-start)+&quot;毫秒&quot;); } public abstract void code(); } public class TestTmp extends Template{ @Override public void code() { int sum = 0; //前面不能有public for(int i=0; i&lt;100000; i++) { sum += i; } System.out.println(sum); } } public class Test { public static void main(String[] args) { TestTmp t= new TestTmp(); t.spendTime(); } }</p>
<p><strong>七、接口：</strong></p>
<p>二刷：</p>
<p>什么是默认方法：public default 返回类型 名称 （参数）{}</p>
<p>接口中不可以用public void test (){......}</p>
<p>而是用public default test(){......} 代替上面方法</p>
<p>接口中可以有什么方法？</p>
<p>非静态abstract方法，没有方法体</p>
<p>非静态default方法，可以有方法体</p>
<p>静态方法，相当于一个不能被子类修改的default方法，只能用 接口名称 . 方法调用</p>
<p>私有方法，只能接口自己用，仅为了解决代码重复的问题</p>
<p>静态属性，即常量</p>
<p>不允许有静态代码块</p>
<p>不允许有构造方法<a href="note://E92FE90708F54FA19F461B927579B32B"><span class="underline">Java基础2.note</span></a></p>
<p>当接口使用了静态方法时，怎么调用？</p>
<p>正确：接口 . 方法</p>
<p>错误：子类 . 方法</p>
<p>为什么接口要用静态方法：只是为了不让子类修改</p>
<p>接口中定义私有方法作用：解决多个默认方法之间重复代码问题，该方法只能在接口中使用</p>
<p>非静态私有方法：解决多个默认方法之间....…不可被子类调用</p>
<p>private 返回值类型 方法名称 (参数列表){</p>
<p>方法体</p>
<p>}</p>
<p>静态私有方法：解决多个静态方法之间.........</p>
<p>private static 返回值类型 方法名称 (参数列表){</p>
<p>方法体</p>
<p>}</p>
<p>接口定义的属性即常量，必须用final，public，static修饰，须赋值，大写。</p>
<p>调用接口属性：System.out.println(a); //直接输出a，不需要写对象.a</p>
<p>调用常量：System.out.println(NUM);</p>
<p>当重名的是两个接口中的default方法时，必须重写该方法，否则报错</p>
<p>不用考虑重名的是抽象方法，因为所有抽象方法必被重写，除非子类也是抽象类</p>
<p>报错：当重名的是两个静态方法，必须修改接口（子类不能重写静态方法），否则子类使用该方法必报错</p>
<p>当重名的是静态方法和非静态方法，不用管，因为调用两者的代码不一样</p>
<p>调用静态方法：接口 . 方法</p>
<p>调用非静态：类名称 . 方法</p>
<p>当重名的是父类方法和接口方法，默认使用父类方法</p>
<p>继承优先于接口</p>
<p>若接口继承自两个接口，且两个父接口有重名的抽象方法，不用理会。因为接口继承后只会有一个该方法，</p>
<p>接口继承接口：用extends</p>
<p>1. 有时必须从几个类中派生出一个子类，继承他们所有的属性和方法。但是Java不支持多重继承。有了接口就可以得到多重继承的效果。</p>
<ol start="4">
<li><p>实现接口类：<strong>class SubClass implements InterfaceA{}</strong></p>
</li>
<li><p>一个类可以实现多个接口，接口也可以继承自其它接口</p>
</li>
<li><p>接口的特点：</p>
</li>
</ol>
<p>（1）用interface来定义</p>
<p>（2）接口中的所有成员变量都默认是有public static final修饰的</p>
<p>（3）接口中的所有方法都默认是由public abstract修饰的</p>
<p>（4）接口没有构造器</p>
<p>（5）接口拥有多层继承机制</p>
<ol start="7">
<li>接口定义举例：</li>
</ol>
<p>public interface Runner{ int id=1; // 等同于public static final int id=1; void start(); // 等同于public abstract void start(); public void run(); // 等同于public abstract void run(); void stop(); // 等同于public abstract void stop(); }</p>
<ol start="8">
<li>包下新建的接口不是class文件，而是interface文件，接口可以继承接口。子类继承父类，只能继承一个父类，类可以实现多个接口，多个接口用逗号分割</li>
</ol>
<p>public class Test1 implements TestIn1, TestIn2{ // implements实现两个事先写好的接口 // 若类没有提供方法体而仅仅只有方法标识，那么这个类一定是一个抽象类。 @Override public void test(){ System.out.println(&quot;1&quot;)； //方法内必须有方法体 } @Override public void test(){ System.out.println(&quot;2&quot;)； } }</p>
<ol start="9">
<li><p>实现接口的类中必须提供接口中所有方法的具体事先内容，方可实例化，否则仍为抽象类</p>
</li>
<li><p>接口的主要用途就是被实现类实现（面向接口编程）</p>
</li>
<li><p>与继承关系类似，接口与实现类之间存在多态性</p>
</li>
<li><p>如果一个类既继承父类，又实现接口，则先写extends，后写implements</p>
</li>
<li><p>抽象类增加新的抽象方法子类就会出现问题，这时抽象类不能代替接口的一个因素，有时我们经常需要给父类添加方法。</p>
</li>
</ol>
<p><strong>当类继承接口后想修改接口：</strong></p>
<p>package demo12; public interface InterDefault { public abstract void test1(); /* 当test1继承该接口后想修改此接口： 写void test3();则继承该接口的类报错 应该写:default void test3() */ default void test3() { } default void test2() { System.out.println(&quot;test2&quot;); } }</p>
<p>package demo12; public class Test1 implements InterDefault{ @Override public void test1() { System.out.println(&quot;test1&quot;); } public static void main(String[] args) { Test1 a = new Test1(); a.test2(); a.test3(); } }</p>
<p>写void test3();则继承该接口的类报错</p>
<p>应该写:default void test3()</p>
<p>八、</p>
<ol>
<li><p>抽象方法只能存在于抽象类或者接口中，但抽象类和接口中却能存在非抽象方法，即有方法体的方法。</p>
</li>
<li><p>类必需实现接口的所有抽象方法。</p>
</li>
<li><p><strong>接口的属性只能是被final，static，public共同修饰的全局常量</strong></p>
</li>
</ol>
<p>interface in1{ int a=10; //默认被...三个共同修饰 void display();//默认被abstract，public共同修饰 } class test implements in1{ public void display(){ System.out.println(&quot;1&quot;);//必须有方法体 } } public class XXX{ public static void main(String[] args){ test t=new test(); t.display(); System.out.println(a); //直接输出a即可，不需要写对象.a } }</p>
<p><strong>接口定义的变量怎么调用？</strong></p>
<p>System.out.println(a); //直接输出a，不需要写对象.a</p>
<p>5. 接口的进一步理解：</p>
<p>interface USB { void read(); void write(); }</p>
<p>然后在写一个U盘类和一个键盘类，这两个类都去实现USB接口。（实现其中的方法）</p>
<p>class YouPan implements USB { @Override public void read() { System.out.println(&quot;U盘正在通过USB功能读取数据&quot;); } @Override public void write() { System.out.println(&quot;U盘正在通过USB功能写入数据&quot;); } }</p>
<p>这是U盘的具体实现。</p>
<p>class JianPan implements USB { @Override public void read() { System.out.println(&quot;键盘正在通过USB功能读取数据&quot;); } @Override public void write() { System.out.println(&quot;键盘正在通过USB功能写入数据&quot;); } }</p>
<p>这是键盘的具体实现。那么，现在U盘和键盘都实现了USB功能，也就是说U盘和键盘都能够调用USB接口中规定的方法，并且他们实现的方式都不一样。</p>
<p>我们在写一个测试，来看看具体的实现：</p>
<p>public class Main { public static void main(String[] args) { //生成一个实现可USB接口（标准）的U盘对象 YouPan youPan = new YouPan(); //调用U盘的read( )方法读取数据 youPan.read(); //调用U盘的write( )方法写入数据 youPan.write(); //生成一个实现可USB接口（标准）的键盘对象 JianPan jianPan = new JianPan(); //调用键盘的read( )方法读取数据 jianPan.read(); //调用键盘的write( )方法写入数据 jianPan.write(); } }</p>
<p>重点：我们不能直接去实例化一个接口，因为接口中的方法都是抽象的，是没有方法体的，这样怎么可能产生具体的实例呢？但是，我们可以使用接口类型的引用指向一个实现了该接口的对象，并且可以调用这个接口中的方法。因此，上图中最后的方法调用我们还可以这样写：（实际上就是使用了Java中多态的特性）</p>
<p>public class Main { public static void main(String[] args) { //生成一个实现可USB接口（标准）的U盘对象 //但是使用一个接口引用指向对象 //USB接口类引用可以指向一个实现了USB接口的对象 USB youPan = new YouPan(); //调用U盘的read( )方法读取数据 youPan.read(); //调用U盘的write( )方法写入数据 youPan.write(); //生成一个实现可USB接口（标准）的键盘对象 //但是使用一个接口引用指向对象 //USB接口类引用可以指向一个实现了USB接口的对象 USB jianPan = new JianPan(); //调用键盘的read( )方法读取数据 jianPan.read(); //调用键盘的write( )方法写入数据 jianPan.write(); } }</p>
<p>2.一个类可以实现不止一个接口。</p>
<p>3.一个接口可以继承于另一个接口，或者另一些接口，接口也可以继承，并且可以多继承。</p>
<p>4.一个类如果要实现某个接口的话，那么它必须要实现这个接口中的所有方法。</p>
<p>5.接口中所有的方法都是抽象的和public的，所有的属性都是public,static,final共同修饰的。</p>
<p>6.接口用来弥补类无法实现多继承的局限。</p>
<p>7.接口也可以用来实现解耦。</p>
<p><strong>附</strong>：</p>
<p>1.Java 接口在JAVA编程语言中是一个抽象类型，是抽象方法的集合，接口通常以interface来声明。一个类通过继承接口的方式，从而来继承接口的抽象方法。</p>
<p>2.接口并不是类，编写接口的方式和类很相似，但是它们属于不同的概念。类描述对象的属性和方法。接口则包含类要实现的方法。</p>
<p>3.除非实现接口的类是抽象类，否则该类要定义接口中的所有方法。</p>
<p>4.接口无法被实例化，但是可以被实现。一个实现接口的类，必须实现接口内所描述的所有方法，否则就必须声明为抽象类。另外，在 Java 中，接口类型可用来声明一个变量，他们可以成为一个空指针，或是被绑定在一个以此接口实现的对象。</p>
<p><strong>5.接口与类相似点：</strong></p>
<p>一个接口可以有多个方法。</p>
<p>接口文件保存在 .java 结尾的文件中，文件名使用接口名。</p>
<p>接口的字节码文件保存在 .class 结尾的文件中。</p>
<p>接口相应的字节码文件必须在与包名称相匹配的目录结构中。</p>
<p>接口与类的区别：</p>
<p>接口不能用于实例化对象。</p>
<p>接口没有构造方法。</p>
<p>接口中所有的方法必须是抽象方法。</p>
<p>接口不能包含成员变量，除了 static 和 final 变量。</p>
<p>接口不是被类继承了，而是要被类实现。</p>
<p>接口支持多继承。</p>
<p>6.接口特性：</p>
<p>接口中每一个方法也是隐式抽象的,接口中的方法会被隐式的指定为 public abstract（只能是 public abstract，其他修饰符都会报错）。</p>
<p>接口中可以含有变量，但是接口中的变量会被隐式的指定为 public static final 变量（并且只能是 public，用 private 修饰会报编译错误）。</p>
<p>接口中的方法是不能在接口中实现的，只能由实现接口的类来实现接口中的方法。</p>
<p><strong>7.抽象类和接口的区别</strong></p>
<p>抽象类中的方法可以有方法体，就是能实现方法的具体功能，但是接口中的方法不行。</p>
<p>抽象类中的成员变量可以是各种类型的，而接口中的成员变量只能是 public static final 类型的。</p>
<p>接口中不能含有静态代码块以及静态方法(用 static 修饰的方法)，而抽象类是可以有静态代码块和静态方法。</p>
<p>一个类只能继承一个抽象类，而一个类却可以实现多个接口。</p>
<p>注：JDK 1.8 以后，接口里可以有静态方法和方法体了。</p>
<p><strong>8. 抽象类很简单</strong></p>
<p>要求只有：抽象类不能被实例化，抽象类的子类必须重写抽象类的所有抽象方法，并提供方法体，不能用abstract修饰属性，私有方法，构造器，静态方法，final的方法</p>
<p><strong>工厂模式</strong></p>
<p><strong>1、工厂方法模式（Factory Method）</strong></p>
<p><em><strong>普通工厂模式</strong></em>，就是建立一个工厂类，对实现了同一接口的一些类进行实例的创建。首先看下关系图：</p>
<p><img src="media/image1.png" alt="clipboard.png">{width=”5.760416666666667in” height=”3.0862510936132983in”}</p>
<p>举例如下：（我们举一个发送邮件和短信的例子）</p>
<p>首先，创建二者的共同接口：内部不要写变量</p>
<p>public interface Sender { public void Send(); }</p>
<p>其次，创建实现类：</p>
<p>public class MailSender implements Sender { @Override public void Send() { System.out.println(&quot;this is mailsender!&quot;); } } public class SmsSender implements Sender { @Override public void Send() { System.out.println(&quot;this is sms sender!&quot;); } }</p>
<p>最后，建工厂类：方法返回的是Sender类型，所以方法必须要用Sender修饰</p>
<p>public class SendFactory { public Sender produce(String type) { if (&quot;mail&quot;.equals(type)) { return new MailSender(); } else if (&quot;sms&quot;.equals(type)) { return new SmsSender(); } else { System.out.println(&quot;请输入正确的类型!&quot;); return null; } } }</p>
<p>我们来测试下：注意接收的对象要用接口Sender修饰</p>
<p>public class FactoryTest { public static void main(String[] args) { SendFactory factory = new SendFactory(); Sender sender = factory.produce(&quot;sms&quot;); sender.Send(); } } // 输出：this is sms sender!</p>
<p><strong>多个工厂方法模式</strong>，是对普通工厂方法模式的改进，在普通工厂方法模式中，如果传递的字符串出错，则不能正确创建对象，而多个工厂方法模式是提供多个工厂方法，分别创建对象。关系图：</p>
<p><img src="media/image2.png" alt="clipboard.png">{width=”5.760416666666667in” height=”2.6338188976377954in”}</p>
<p>将上面的代码做下修改，改动下SendFactory类就行，如下：</p>
<p>public class SendFactory { public Sender produceMail(){ return new MailSender(); } public Sender produceSms(){ return new SmsSender(); } }</p>
<p>测试类如下：</p>
<p>public class FactoryTest { public static void main(String[] args) { SendFactory factory = new SendFactory(); Sender sender = factory.produceMail(); sender.Send(); } } // 输出：this is mailsender!</p>
<p><em><strong>3、静态工厂方法模式</strong></em>，将上面的多个工厂方法模式里的方法置为静态的，不需要创建实例，直接调用即可。</p>
<p>public class SendFactory { public static Sender produceMail(){ return new MailSender(); } public static Sender produceSms(){ return new SmsSender(); } } public class FactoryTest { public static void main(String[] args) { Sender sender = SendFactory.produceMail(); sender.Send(); } } // 输出：this is mailsender!</p>
<p>public class Test { public static void main(String[] args) { Provider provider = new SendMailFactory(); Sender sender = provider.produce(); sender.Send(); } }</p>
<p>总体来说，工厂模式适合：凡是出现了大量的产品需要创建，并且具有共同的接口时，可以通过工厂方法模式进行创建。在以上的三种模式中，第一种如果传入的字符串有误，不能正确创建对象，第三种相对于第二种，不需要实例化工厂类，所以，大多数情况下，我们会选用第三种——静态工厂方法模式。</p>
<p><strong>2、抽象工厂模式（Abstract Factory）</strong></p>
<p>工厂方法模式有一个问题就是，类的创建依赖工厂类，也就是说，如果想要拓展程序，必须对工厂类进行修改，这违背了闭包原则，所以，从设计角度考虑，有一定的问题，如何解决？就用到抽象工厂模式，创建多个工厂类，这样一旦需要增加新的功能，直接增加新的工厂类就可以了，不需要修改之前的代码。因为抽象工厂不太好理解，我们先看看图，然后就和代码，就比较容易理解。</p>
<p><img src="media/image3.png" alt="clipboard.png">{width=”5.760416666666667in” height=”2.34713145231846in”}</p>
<p>请看例子：</p>
<p>public interface Sender { public void Send(); }</p>
<p>两个实现类：</p>
<p>public class MailSender implements Sender { @Override public void Send() { System.out.println(&quot;this is mailsender!&quot;); } } public class SmsSender implements Sender { @Override public void Send() { System.out.println(&quot;this is sms sender!&quot;); } }</p>
<p>两个工厂类：</p>
<p>public class SendMailFactory implements Provider { @Override public Sender produce(){ return new MailSender(); } } public class SendSmsFactory implements Provider{ @Override public Sender produce() { return new SmsSender(); } }</p>
<p>在提供一个接口：</p>
<p>public interface Provider { public Sender produce(); }</p>
<p>测试类：</p>
<p>其实这个模式的好处就是，如果你现在想增加一个功能：发及时信息，则只需做一个实现类，实现Sender接口，同时做一个工厂类，实现Provider接口，就OK了，无需去改动现成的代码。这样做，拓展性较好！</p>
<p><strong>内部类</strong></p>
<p>一个类定义在另一个类的内部，前者称为内部类，后者称为外部类</p>
<p>外部类要访问内部类中的成员，需要格式如下：内部类. 成员或内部类对象. 成员</p>
<p>new A().setTest();</p>
<p>分类：<strong>成员内部类</strong>：（static成员内部类和非static成员内部类）</p>
<p><strong>局部内部类</strong>：（不谈修饰符）、匿名内部类</p>
<p>4. 内部类如何访问外部类的属性方法：</p>
<p>外部类名称 . this 对象名</p>
<p>5. 什么是局部内部类：</p>
<p>方法内定义一个类</p>
<p><strong>6. 搞懂下列语句</strong></p>
<p>System.out.println(new Test3().new A().i); //外部类输出非静态内部类的属性 Test3.this.i=1; //在内部类调用外部类的属性 new Test3().this.i=1; //错误 this.i = 2; //外部类调用外部类属性，或内部类调用内部类属性 new A().setInfo(); //在外部类调用内部类的方法</p>
<p>package demo7; // 切记非静态常量只有new了才可以使用 public class Test3 { int i; public int z; private int k; class A{ public int i; public void setTest(){ // 外部类的i不属于A类及其所有父类，所以无法直接用this和super， // 外部类i非静态，所以只能用Test3.this.i // 若i是static，则只能用Test3.i // 此处没有实例化，只能用this才可以调用i Test3.this.i=1; Test3.this.z=2; Test3.this.k=3; // 只有实例化对象了才可以调用非静态方法，而调用了该方法后就可以使用this // 但如果该方法是静态的，则不能用this而应该直接 i=0; this.i=0; } public void setA(){ this.i = 10; } } // 外部类如何调用内部类? public void setInfo() { // 不是new A.setTest new A().setTest(); } // this必须要在非静态方法内才能使用 // 静态方法内严禁用非静态变量及方法，与this相悖 public static void main(String[] args) { System.out.println(B.this.i); // 报错 } public void showInfo() { System.out.println(this.i); System.out.println(this.z); System.out.println(this.k); System.out.println(B.this.k); //报错 System.out.println(new Test3.A().i); } public static void main(String[] args) { Test3 t=new Test3(); t.setInfo(); t.showInfo(); // 如何调用内部类的属性方法 System.out.println(new Test3().new A().i); System.out.println(new Test3.A().i); //报错 System.out.println(Test3.this.i); } }</p>
<p>内部类的作用：解决Java不能多重继承的问题</p>
<p>package demo7; public class Test4 { public static void main(String[] args) { A a = new A(); a.testB(); a.testC(); } } // 写public class A是错误的 class A{ public void testB() { new InnerB().testD(); } public void testC() { new InnerC().testC(); } private class InnerB extends D{ @Override public void testD() { System.out.println(&quot;D&quot;); } } private class InnerC extends C{ @Override public void testC() { System.out.println(&quot;C&quot;); } } } // 类A想同时获得类 D,C的方法 abstract class D{ public abstract void testD(); } class C{ public void testC() { } }</p>
<p>附：</p>
<p>1. equal()除了特殊类(重写了该方法)外和”=”一样都是比较栈的地址，基本数据类型都是存放在栈中，没有存放在堆中，且栈中不会出现多个地址内容相同的情况，栈中一个值只会有一个地址。比较栈的地址即相当于比较基本类型的值</p>
<p>equal在特殊类中比较的是堆的地址（即栈的内容，比较的是值）</p>
<p>2. 非静态方法切记只能new了才可以用</p>
<p>3. String类型怎么转为其他类型？其他类型怎么相互转换？</p>
<p><strong>匿名内部类</strong></p>
<p><strong>匿名内部类和匿名对象不是一回事</strong></p>
<p>先定义一个接口 Interface()</p>
<p>在main内：</p>
<p>一、有名字的匿名内部类：</p>
<p><strong>尾部有分号</strong></p>
<p>并没有创建新类</p>
<p>可以多次使用obj . method()；</p>
<p>Interface obj = new Interface(){ @Override public void method(){ ......... } }; obj.method();</p>
<p>二、没名字的匿名内部类</p>
<p><strong>这个例子很重要！</strong></p>
<p>public interface Skill{ abstract void use(); } public class PersonSkill{ private Skill skill; public PersonSkill(Skill skill) {this.skill = skill;} public static void main(String... args) { new PersonSkill(new Skill() { @Override public void use() { System.out.println(&quot;this is use();&quot;); } }).skill.use(); } }</p>
<p><strong>末尾直接 . method()；</strong></p>
<p>只能使用一次</p>
<p><strong>三、练习：接口作为成员变量类型</strong></p>
<p>先定义个接口</p>
<p>public interface Skill { abstract void use(); }</p>
<p>public class Hero{ private String name; private Skill skill; public void setSkill(Skill skill) { this.skill = skill; } }</p>
<p>如何给Hero类的对象赋予skill值？</p>
<p>建立一个类继承该Skill接口并重写接口的方法，再</p>
<p>public class ADCSkill implements Skill{ @Override public void use() { System.out.println(&quot;射击ADC&quot;); } } Hero hero = new Hero(); hero.setSkill(new ADCSkill())；</p>
<p>2.</p>
<p>Skill skill = new Skill() { @Override public void use() { System.out.println(&quot;肉坦&quot;); } }; hero.setSkill(skill);</p>
<p>3.</p>
<p>hero.setSkill(new Skill(){ @Override public void use() { System.out.println(&quot;法师&quot;); } });</p>
 
      <!-- reward -->
      
      <div id="reword-out">
        <div id="reward-btn">
          Donate
        </div>
      </div>
      
    </div>
    

    <!-- copyright -->
    
    <div class="declare">
      <ul class="post-copyright">
        <li>
          <i class="ri-copyright-line"></i>
          <strong>Copyright： </strong>
          
          Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.
          
        </li>
      </ul>
    </div>
    
    <footer class="article-footer">
       
<div class="share-btn">
      <span class="share-sns share-outer">
        <i class="ri-share-forward-line"></i>
        分享
      </span>
      <div class="share-wrap">
        <i class="arrow"></i>
        <div class="share-icons">
          
          <a class="weibo share-sns" href="javascript:;" data-type="weibo">
            <i class="ri-weibo-fill"></i>
          </a>
          <a class="weixin share-sns wxFab" href="javascript:;" data-type="weixin">
            <i class="ri-wechat-fill"></i>
          </a>
          <a class="qq share-sns" href="javascript:;" data-type="qq">
            <i class="ri-qq-fill"></i>
          </a>
          <a class="douban share-sns" href="javascript:;" data-type="douban">
            <i class="ri-douban-line"></i>
          </a>
          <!-- <a class="qzone share-sns" href="javascript:;" data-type="qzone">
            <i class="icon icon-qzone"></i>
          </a> -->
          
          <a class="facebook share-sns" href="javascript:;" data-type="facebook">
            <i class="ri-facebook-circle-fill"></i>
          </a>
          <a class="twitter share-sns" href="javascript:;" data-type="twitter">
            <i class="ri-twitter-fill"></i>
          </a>
          <a class="google share-sns" href="javascript:;" data-type="google">
            <i class="ri-google-fill"></i>
          </a>
        </div>
      </div>
</div>

<div class="wx-share-modal">
    <a class="modal-close" href="javascript:;"><i class="ri-close-circle-line"></i></a>
    <p>扫一扫，分享到微信</p>
    <div class="wx-qrcode">
      <img src="//api.qrserver.com/v1/create-qr-code/?size=150x150&data=https://gitee.com/zhang-shuo-fr/hexo1.git/2019/08/13/java%E5%9F%BA%E7%A1%80/%E9%9A%8F%E7%AC%94/" alt="微信分享二维码">
    </div>
</div>

<div id="share-mask"></div>  
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/hexo1/tags/java%E5%9F%BA%E7%A1%80%E9%9A%8F%E7%AC%941-%E8%AF%B4%E6%98%8E%EF%BC%9A%E6%96%87%E7%AB%A0%E6%A0%87%E7%AD%BE/" rel="tag">java基础随笔1#说明：文章标签</a></li></ul>

    </footer>
  </div>

   
  <nav class="article-nav">
    
      <a href="/hexo1/2019/08/13/java%E5%9F%BA%E7%A1%80/%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E6%80%BB%E7%BB%93/" class="article-nav-link">
        <strong class="article-nav-caption">上一篇</strong>
        <div class="article-nav-title">
          
            面向对象总结
          
        </div>
      </a>
    
    
      <a href="/hexo1/2019/08/13/java%E5%9F%BA%E7%A1%80/%E7%AC%94%E8%AE%B01/" class="article-nav-link">
        <strong class="article-nav-caption">下一篇</strong>
        <div class="article-nav-title">初学java</div>
      </a>
    
  </nav>

   
<!-- valine评论 -->
<div id="vcomments-box">
  <div id="vcomments"></div>
</div>
<script src="//cdn1.lncld.net/static/js/3.0.4/av-min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/valine@1.4.14/dist/Valine.min.js"></script>
<script>
  new Valine({
    el: "#vcomments",
    app_id: "",
    app_key: "",
    path: window.location.pathname,
    avatar: "monsterid",
    placeholder: "给我的文章加点评论吧~",
    recordIP: true,
  });
  const infoEle = document.querySelector("#vcomments .info");
  if (infoEle && infoEle.childNodes && infoEle.childNodes.length > 0) {
    infoEle.childNodes.forEach(function (item) {
      item.parentNode.removeChild(item);
    });
  }
</script>
<style>
  #vcomments-box {
    padding: 5px 30px;
  }

  @media screen and (max-width: 800px) {
    #vcomments-box {
      padding: 5px 0px;
    }
  }

  #vcomments-box #vcomments {
    background-color: #fff;
  }

  .v .vlist .vcard .vh {
    padding-right: 20px;
  }

  .v .vlist .vcard {
    padding-left: 10px;
  }
</style>

 
   
     
</article>

</section>
      <footer class="footer">
  <div class="outer">
    <ul>
      <li>
        Copyrights &copy;
        2020-2021
        <i class="ri-heart-fill heart_icon"></i> Zhang Shuo
      </li>
    </ul>
    <ul>
      <li>
        
      </li>
    </ul>
    <ul>
      <li>
        
        
        <span>
  <span><i class="ri-user-3-fill"></i>Visitors:<span id="busuanzi_value_site_uv"></span></span>
  <span class="division">|</span>
  <span><i class="ri-eye-fill"></i>Views:<span id="busuanzi_value_page_pv"></span></span>
</span>
        
      </li>
    </ul>
    <ul>
      
    </ul>
    <ul>
      
    </ul>
    <ul>
      <li>
        <!-- cnzz统计 -->
        
        <script type="text/javascript" src=''></script>
        
      </li>
    </ul>
  </div>
</footer>    
    </main>
    <div class="float_btns">
      <div class="totop" id="totop">
  <i class="ri-arrow-up-line"></i>
</div>

<div class="todark" id="todark">
  <i class="ri-moon-line"></i>
</div>

    </div>
    <aside class="sidebar on">
      <button class="navbar-toggle"></button>
<nav class="navbar">
  
  <div class="logo">
    <a href="/hexo1/"><img src="/hexo1/images/ayer-side.svg" alt="Zhang Shuo&#39;s Studio"></a>
  </div>
  
  <ul class="nav nav-main">
    
    <li class="nav-item">
      <a class="nav-item-link" href="/hexo1/">主页</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/hexo1/archives">归档</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/hexo1/categories">分类</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/hexo1/tags">标签</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/hexo1/tags/%E6%97%85%E8%A1%8C/">旅行</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" target="_blank" rel="noopener" href="http://shenyu-vip.lofter.com">摄影</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/hexo1/2019/about">关于我</a>
    </li>
    
  </ul>
</nav>
<nav class="navbar navbar-bottom">
  <ul class="nav">
    <li class="nav-item">
      
      <a class="nav-item-link nav-item-search"  title="Search">
        <i class="ri-search-line"></i>
      </a>
      
      
      <a class="nav-item-link" target="_blank" href="/hexo1/atom.xml" title="RSS Feed">
        <i class="ri-rss-line"></i>
      </a>
      
    </li>
  </ul>
</nav>
<div class="search-form-wrap">
  <div class="local-search local-search-plugin">
  <input type="search" id="local-search-input" class="local-search-input" placeholder="Search...">
  <div id="local-search-result" class="local-search-result"></div>
</div>
</div>
    </aside>
    <div id="mask"></div>

<!-- #reward -->
<div id="reward">
  <span class="close"><i class="ri-close-line"></i></span>
  <p class="reward-p"><i class="ri-cup-line"></i>请我喝杯咖啡吧~</p>
  <div class="reward-box">
    
    <div class="reward-item">
      <img class="reward-img" src="/hexo1/images/alipay.jpg">
      <span class="reward-type">支付宝</span>
    </div>
    
    
    <div class="reward-item">
      <img class="reward-img" src="/hexo1/images/wechat.jpg">
      <span class="reward-type">微信</span>
    </div>
    
  </div>
</div>
    
<script src="/hexo1/js/jquery-3.6.0.min.js"></script>
 
<script src="/hexo1/js/lazyload.min.js"></script>

<!-- Tocbot -->
 
<script src="/hexo1/js/tocbot.min.js"></script>

<script>
  tocbot.init({
    tocSelector: ".tocbot",
    contentSelector: ".article-entry",
    headingSelector: "h1, h2, h3, h4, h5, h6",
    hasInnerContainers: true,
    scrollSmooth: true,
    scrollContainer: "main",
    positionFixedSelector: ".tocbot",
    positionFixedClass: "is-position-fixed",
    fixedSidebarOffset: "auto",
  });
</script>

<script src="https://cdn.jsdelivr.net/npm/jquery-modal@0.9.2/jquery.modal.min.js"></script>
<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/jquery-modal@0.9.2/jquery.modal.min.css"
/>
<script src="https://cdn.jsdelivr.net/npm/justifiedGallery@3.7.0/dist/js/jquery.justifiedGallery.min.js"></script>

<script src="/hexo1/dist/main.js"></script>

<!-- ImageViewer -->
 <!-- Root element of PhotoSwipe. Must have class pswp. -->
<div class="pswp" tabindex="-1" role="dialog" aria-hidden="true">

    <!-- Background of PhotoSwipe. 
         It's a separate element as animating opacity is faster than rgba(). -->
    <div class="pswp__bg"></div>

    <!-- Slides wrapper with overflow:hidden. -->
    <div class="pswp__scroll-wrap">

        <!-- Container that holds slides. 
            PhotoSwipe keeps only 3 of them in the DOM to save memory.
            Don't modify these 3 pswp__item elements, data is added later on. -->
        <div class="pswp__container">
            <div class="pswp__item"></div>
            <div class="pswp__item"></div>
            <div class="pswp__item"></div>
        </div>

        <!-- Default (PhotoSwipeUI_Default) interface on top of sliding area. Can be changed. -->
        <div class="pswp__ui pswp__ui--hidden">

            <div class="pswp__top-bar">

                <!--  Controls are self-explanatory. Order can be changed. -->

                <div class="pswp__counter"></div>

                <button class="pswp__button pswp__button--close" title="Close (Esc)"></button>

                <button class="pswp__button pswp__button--share" style="display:none" title="Share"></button>

                <button class="pswp__button pswp__button--fs" title="Toggle fullscreen"></button>

                <button class="pswp__button pswp__button--zoom" title="Zoom in/out"></button>

                <!-- Preloader demo http://codepen.io/dimsemenov/pen/yyBWoR -->
                <!-- element will get class pswp__preloader--active when preloader is running -->
                <div class="pswp__preloader">
                    <div class="pswp__preloader__icn">
                        <div class="pswp__preloader__cut">
                            <div class="pswp__preloader__donut"></div>
                        </div>
                    </div>
                </div>
            </div>

            <div class="pswp__share-modal pswp__share-modal--hidden pswp__single-tap">
                <div class="pswp__share-tooltip"></div>
            </div>

            <button class="pswp__button pswp__button--arrow--left" title="Previous (arrow left)">
            </button>

            <button class="pswp__button pswp__button--arrow--right" title="Next (arrow right)">
            </button>

            <div class="pswp__caption">
                <div class="pswp__caption__center"></div>
            </div>

        </div>

    </div>

</div>

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/photoswipe.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/default-skin/default-skin.min.css">
<script src="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/photoswipe.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/photoswipe-ui-default.min.js"></script>

<script>
    function viewer_init() {
        let pswpElement = document.querySelectorAll('.pswp')[0];
        let $imgArr = document.querySelectorAll(('.article-entry img:not(.reward-img)'))

        $imgArr.forEach(($em, i) => {
            $em.onclick = () => {
                // slider展开状态
                // todo: 这样不好，后面改成状态
                if (document.querySelector('.left-col.show')) return
                let items = []
                $imgArr.forEach(($em2, i2) => {
                    let img = $em2.getAttribute('data-idx', i2)
                    let src = $em2.getAttribute('data-target') || $em2.getAttribute('src')
                    let title = $em2.getAttribute('alt')
                    // 获得原图尺寸
                    const image = new Image()
                    image.src = src
                    items.push({
                        src: src,
                        w: image.width || $em2.width,
                        h: image.height || $em2.height,
                        title: title
                    })
                })
                var gallery = new PhotoSwipe(pswpElement, PhotoSwipeUI_Default, items, {
                    index: parseInt(i)
                });
                gallery.init()
            }
        })
    }
    viewer_init()
</script> 
<!-- MathJax -->

<!-- Katex -->

<!-- busuanzi  -->
 
<script src="/hexo1/js/busuanzi-2.3.pure.min.js"></script>
 
<!-- ClickLove -->

<!-- ClickBoom1 -->

<!-- ClickBoom2 -->

<!-- CodeCopy -->
 
<link rel="stylesheet" href="/hexo1/css/clipboard.css">
 <script src="https://cdn.jsdelivr.net/npm/clipboard@2/dist/clipboard.min.js"></script>
<script>
  function wait(callback, seconds) {
    var timelag = null;
    timelag = window.setTimeout(callback, seconds);
  }
  !function (e, t, a) {
    var initCopyCode = function(){
      var copyHtml = '';
      copyHtml += '<button class="btn-copy" data-clipboard-snippet="">';
      copyHtml += '<i class="ri-file-copy-2-line"></i><span>COPY</span>';
      copyHtml += '</button>';
      $(".highlight .code pre").before(copyHtml);
      $(".article pre code").before(copyHtml);
      var clipboard = new ClipboardJS('.btn-copy', {
        target: function(trigger) {
          return trigger.nextElementSibling;
        }
      });
      clipboard.on('success', function(e) {
        let $btn = $(e.trigger);
        $btn.addClass('copied');
        let $icon = $($btn.find('i'));
        $icon.removeClass('ri-file-copy-2-line');
        $icon.addClass('ri-checkbox-circle-line');
        let $span = $($btn.find('span'));
        $span[0].innerText = 'COPIED';
        
        wait(function () { // 等待两秒钟后恢复
          $icon.removeClass('ri-checkbox-circle-line');
          $icon.addClass('ri-file-copy-2-line');
          $span[0].innerText = 'COPY';
        }, 2000);
      });
      clipboard.on('error', function(e) {
        e.clearSelection();
        let $btn = $(e.trigger);
        $btn.addClass('copy-failed');
        let $icon = $($btn.find('i'));
        $icon.removeClass('ri-file-copy-2-line');
        $icon.addClass('ri-time-line');
        let $span = $($btn.find('span'));
        $span[0].innerText = 'COPY FAILED';
        
        wait(function () { // 等待两秒钟后恢复
          $icon.removeClass('ri-time-line');
          $icon.addClass('ri-file-copy-2-line');
          $span[0].innerText = 'COPY';
        }, 2000);
      });
    }
    initCopyCode();
  }(window, document);
</script>
 
<!-- CanvasBackground -->

<script>
  if (window.mermaid) {
    mermaid.initialize({ theme: "forest" });
  }
</script>


    
    <div id="music">
    
    
    
    <iframe frameborder="no" border="1" marginwidth="0" marginheight="0" width="200" height="52"
        src="//music.163.com/outchain/player?type=2&id=22707008&auto=1&height=32"></iframe>
</div>

<style>
    #music {
        position: fixed;
        right: 15px;
        bottom: 0;
        z-index: 998;
    }
</style>
    
    

  </div>
</body>

</html>